SELECTOR_KERNEL_CS  equ 8

; 导入函数
extern  cstart
extern  exception_handler
extern  spurious_irq

; 导入全局变量
extern  gdt_ptr
extern  idt_ptr
extern  disp_pos


[SECTION .bss]
StackSpace      resb    2 * 1024
StackTop:       ; 栈顶

[section .text] ; 代码在此

global _start   ; 导出 _start

global  divide_error
global  single_step_exception
global  nmi
global  breakpoint_exception
global  overflow
global  bounds_check
global  inval_opcode
global  copr_not_available
global  double_fault
global  copr_seg_overrun
global  inval_tss
global  segment_not_present
global  stack_exception
global  general_protection
global  page_fault
global  copr_error
global  hwint00
global  hwint01
global  hwint02
global  hwint03
global  hwint04
global  hwint05
global  hwint06
global  hwint07
global  hwint08
global  hwint09
global  hwint10
global  hwint11
global  hwint12
global  hwint13
global  hwint14
global  hwint15

_start:

    ; 把 esp 从 LOADER 挪到 KERNEL
    mov esp, StackTop   ; 堆栈在 bss 段中

    mov dword [disp_pos], 0

    sgdt    [gdt_ptr]   ; cstart() 中将会用到 gdt_ptr
    call    cstart      ; 在此函数中改变了gdt_ptr，让它指向新的GDT
    lgdt    [gdt_ptr]   ; 使用新的GDT

    lidt    [idt_ptr]

    jmp SELECTOR_KERNEL_CS:csinit
csinit:
    sti
    ;hlt
    jmp $


; 中断和异常 -- 硬件中断
; ---------------------------------
%macro  hwint_master    1
        push    %1
        call    spurious_irq
        add     esp, 4
        ;hlt
        mov al,20h  ; AL = EOI
        out 20h,al      ; 发送EOI到主8529A
        sti         ; 允许CPU响应中断     iret

%endmacro
; ---------------------------------

ALIGN   16  ; 设置16字节对齐的宏，下同
hwint00: hwint_master 0     ; Interrupt routine for irq 0 (the clock).
ALIGN   16
hwint01: hwint_master 1     ; Interrupt routine for irq 1 (keyboard)
ALIGN   16
hwint02: hwint_master 2     ; Interrupt routine for irq 2 (cascade!)
ALIGN   16
hwint03: hwint_master 3     ; Interrupt routine for irq 3 (second serial)
ALIGN   16
hwint04: hwint_master 4     ; Interrupt routine for irq 4 (first serial)
ALIGN   16
hwint05: hwint_master 5     ; Interrupt routine for irq 5 (XT winchester)
ALIGN   16
hwint06: hwint_master 6     ; Interrupt routine for irq 6 (floppy)
ALIGN   16
hwint07: hwint_master 7     ; Interrupt routine for irq 7 (printer)
        

; ---------------------------------
%macro  hwint_slave     1
        push    %1
        call    spurious_irq
        add     esp, 4
        hlt
%endmacro
; ---------------------------------

ALIGN   16
hwint08: hwint_slave 8      ; Interrupt routine for irq 8 (realtime clock).
ALIGN   16
hwint09: hwint_slave 9      ; Interrupt routine for irq 9 (irq 2 redirected)
ALIGN   16
hwint10: hwint_slave 10     ; Interrupt routine for irq 10
ALIGN   16
hwint11: hwint_slave 11     ; Interrupt routine for irq 11
ALIGN   16
hwint12: hwint_slave 12     ; Interrupt routine for irq 12
ALIGN   16
hwint13: hwint_slave 13     ; Interrupt routine for irq 13 (FPU exception)
ALIGN   16
hwint14: hwint_slave 14     ; Interrupt routine for irq 14 (AT winchester)
ALIGN   16
hwint15: hwint_slave 15     ; Interrupt routine for irq 15
        

; 中断和异常 -- 异常
divide_error:
    push    0xFFFFFFFF  ; no err code
    push    0       ; vector_no = 0
    jmp exception
single_step_exception:
    push    0xFFFFFFFF  ; no err code
    push    1       ; vector_no = 1
    jmp exception
nmi:
    push    0xFFFFFFFF  ; no err code
    push    2       ; vector_no = 2
    jmp exception
breakpoint_exception:
    push    0xFFFFFFFF  ; no err code
    push    3       ; vector_no = 3
    jmp exception
overflow:
    push    0xFFFFFFFF  ; no err code
    push    4       ; vector_no = 4
    jmp exception
bounds_check:
    push    0xFFFFFFFF  ; no err code
    push    5       ; vector_no = 5
    jmp exception
inval_opcode:
    push    0xFFFFFFFF  ; no err code
    push    6       ; vector_no = 6
    jmp exception
copr_not_available:
    push    0xFFFFFFFF  ; no err code
    push    7       ; vector_no = 7
    jmp exception
double_fault:
    push    8       ; vector_no = 8
    jmp exception
copr_seg_overrun:
    push    0xFFFFFFFF  ; no err code
    push    9       ; vector_no = 9
    jmp exception
inval_tss:
    push    10      ; vector_no = A
    jmp exception
segment_not_present:
    push    11      ; vector_no = B
    jmp exception
stack_exception:
    push    12      ; vector_no = C
    jmp exception
general_protection:
    push    13      ; vector_no = D
    jmp exception
page_fault:
    push    14      ; vector_no = E
    jmp exception
copr_error:
    push    0xFFFFFFFF  ; no err code
    push    16      ; vector_no = 10h
    jmp exception

exception:
    call    exception_handler
    add esp, 4*2    ; 让栈顶指向 EIP，堆栈中从顶向下依次是：EIP、CS、EFLAGS
    hlt
